package bomberman.entity;

import gameframework.base.Drawable;
import gameframework.base.DrawableImage;
import gameframework.base.Overlappable;
import gameframework.game.GameEntity;
import gameframework.game.GameMovable;
import gameframework.game.MoveBlocker;

import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;


import bomberman.BombermanGameLevel;



public class Bomb extends GameMovable implements Drawable, GameEntity, MoveBlocker, Overlappable{

	protected static DrawableImage image = null;
	protected int bombTimer = 40;
	protected int bombTimerBase;
	//bomb power
	protected int actionField;
	protected Bomberman player;
	protected Canvas defaultCanvas;
	protected int spriteType = 0;
	protected int spriteNumber = 0;
	private final int SPRITE_HEIGHT = 12;
	private  final int SPRITE_WIDTH = 11;
	
	//avoid a bug with chain reaction
	private boolean canExplode = true;
	
	public Bomb(Canvas defaultCanvas, Point pos, Bomberman player, int power) {
		if (image == null) {
			image = new DrawableImage("images/bomb.png", defaultCanvas);
		}
		setPosition(pos);
		this.player = player;
		this.defaultCanvas = defaultCanvas;
		this.actionField = power;
		bombTimerBase = bombTimer;
	}

	public void draw(Graphics g) {
		
		spriteType = bombTimer % 2;
		if(bombTimer < bombTimerBase / 3)
			spriteNumber = 2;
		else if(bombTimer < (bombTimerBase / 3) * 2)
			spriteNumber = 1;
		else
			spriteNumber = 0;
		g.drawImage(image.getImage(), (int) getPosition().getX(),
				(int) getPosition().getY(), (int) getPosition().getX()
						+ BombermanGameLevel.SPRITE_SIZE,
				(int) getPosition().getY() + BombermanGameLevel.SPRITE_SIZE, 
				spriteNumber * SPRITE_WIDTH,
				spriteType * SPRITE_HEIGHT, 
				(spriteNumber + 1) * SPRITE_WIDTH,
				(spriteType + 1) * SPRITE_HEIGHT, null);
	}

	public Rectangle getBoundingBox() {
		return (new Rectangle((int) getPosition().getX(), (int) getPosition().getY(),
				BombermanGameLevel.SPRITE_SIZE, BombermanGameLevel.SPRITE_SIZE));
	}
	
	private boolean isUnbreakableWall(double x, double y, Set<Wall> walls){
		for (Wall w : walls)
			if (w.getPos().getX() == x && w.getPos().getY() == y)
				return w instanceof UnbreakableWall;
		return false;
	}
	
	private int isWall(double x, double y, Set<Wall> walls){
		for (Wall w : walls)
			if (w.getPos().getX() == x && w.getPos().getY() == y)
			{
				if (w instanceof UnbreakableWall)
					return 1;
				else
				{
					if (w instanceof BreakableWall)
						return 2;
					else
						break;
				}
			}
		
		return 0;
	}
	
	//Create fire in the action field of the bomb
	//Stopped the fire on the first wall met
	private void fire(Set<Wall> walls){
		boolean stop = false;
		int val;
		
		int maxSouth = (int)getPosition().getY()+actionField*BombermanGameLevel.SPRITE_SIZE;
		//south direction
		for (int i = (int)getPosition().getY() + BombermanGameLevel.SPRITE_SIZE ; i < maxSouth ; i+=BombermanGameLevel.SPRITE_SIZE)
		{
			val = isWall(getPosition().getX(), i, walls);
			if (val == 1)
			{
				stop = true;
				break;
			}
			BombermanGameLevel.medUniverse.getUniverse().addGameEntity(new Fire(defaultCanvas,
					new Point((int) getPosition().getX(),i), BombermanGameLevel.medUniverse.getUniverse(), Fire.SOUTH));
			if (val == 2)
			{
				stop = true;
				break;
			}
		}
		if(!stop && !isUnbreakableWall(getPosition().getX(), maxSouth, walls))
			BombermanGameLevel.medUniverse.getUniverse().addGameEntity(new Fire(defaultCanvas,
				new Point((int) getPosition().getX(),maxSouth), BombermanGameLevel.medUniverse.getUniverse(), Fire.END_SOUTH));
		stop = false;
		
		int maxNorth = (int)getPosition().getY()-actionField*BombermanGameLevel.SPRITE_SIZE;
		//north direction
		for (int i = (int)getPosition().getY() - BombermanGameLevel.SPRITE_SIZE; i > maxNorth ; i-=BombermanGameLevel.SPRITE_SIZE)
		{
			val = isWall(getPosition().getX(), i, walls);
			if (val == 1)
			{
				stop = true;
				break;
			}
			BombermanGameLevel.medUniverse.getUniverse().addGameEntity(new Fire(defaultCanvas,
					new Point((int) getPosition().getX(),i), BombermanGameLevel.medUniverse.getUniverse(), Fire.NORTH));
			if (val == 2)
			{
				stop = true;
				break;
			}
		}
		if (!stop && !isUnbreakableWall(getPosition().getX(), maxNorth, walls))
			BombermanGameLevel.medUniverse.getUniverse().addGameEntity(new Fire(defaultCanvas,
				new Point((int) getPosition().getX(),maxNorth), BombermanGameLevel.medUniverse.getUniverse(), Fire.END_NORTH));
		stop = false;
		
		int maxEast = (int)getPosition().getX()+actionField*BombermanGameLevel.SPRITE_SIZE;
		//east direction
		for (int i = (int)getPosition().getX() + BombermanGameLevel.SPRITE_SIZE; i < maxEast; i+=BombermanGameLevel.SPRITE_SIZE)
		{
			val = isWall(i, getPosition().getY(), walls);
			if (val == 1)
			{
				stop = true;
				break;
			}
			BombermanGameLevel.medUniverse.getUniverse().addGameEntity(new Fire(defaultCanvas,
					new Point(i,(int) getPosition().getY()), BombermanGameLevel.medUniverse.getUniverse(), Fire.EAST));
			if (val == 2)
			{
				stop = true;
				break;
			}
		}
		if(!stop && !isUnbreakableWall(maxEast, getPosition().getY(), walls))
			BombermanGameLevel.medUniverse.getUniverse().addGameEntity(new Fire(defaultCanvas,
				new Point(maxEast,(int) getPosition().getY()), BombermanGameLevel.medUniverse.getUniverse(), Fire.END_EAST));
		stop = false;
		
		int maxWest = (int)getPosition().getX()-actionField*BombermanGameLevel.SPRITE_SIZE;
		//west direction
		for (int i = (int)getPosition().getX() - BombermanGameLevel.SPRITE_SIZE ; i > maxWest ; i-=BombermanGameLevel.SPRITE_SIZE)
		{
			val = isWall(i, getPosition().getY(), walls);
			if (val == 1)
			{
				stop = true;
				break;
			}
			BombermanGameLevel.medUniverse.getUniverse().addGameEntity(new Fire(defaultCanvas,
					new Point(i,(int) getPosition().getY()), BombermanGameLevel.medUniverse.getUniverse(), Fire.WEST));
			if (val == 2)
			{
				stop = true;
				break;
			}
		}
		if(!stop && !isUnbreakableWall(maxWest, getPosition().getY(), walls))
			BombermanGameLevel.medUniverse.getUniverse().addGameEntity(new Fire(defaultCanvas,
				new Point(maxWest,(int) getPosition().getY()), BombermanGameLevel.medUniverse.getUniverse(), Fire.END_WEST));
		
		//center fire
		BombermanGameLevel.medUniverse.getUniverse().addGameEntity(new Fire(defaultCanvas,
				new Point((int) getPosition().getX(),(int) getPosition().getY()), BombermanGameLevel.medUniverse.getUniverse(), Fire.MIDDLE));
	}
	
	public void bombExplode(){
		if (canExplode){
			canExplode = false;
			Iterator<GameEntity> itge = BombermanGameLevel.medUniverse.getUniverse().gameEntities();
			GameEntity ge = itge.next();
			Set<Wall> walls = new HashSet<Wall>();
			
			//we check if there is a fire in the action field
			//of the bomb
			while(itge.hasNext())
			{
				if(ge instanceof Wall && isInActionField(((Wall)ge).getPos()))
					walls.add((Wall)ge);
					
				ge = itge.next();
			}
			
			fire(walls);
			
			player.upNumberOfBombs();
			BombermanGameLevel.medUniverse.getUniverse().removeGameEntity(this);
		}
	}
	
	public void oneStepMoveHandler(){
		if(bombTimer-- == 0)
			bombExplode();
	}
	
	public boolean isInActionField(Point pos){
		if (pos.distance(getPosition())/BombermanGameLevel.SPRITE_SIZE <= actionField &&
				(pos.getX() == getPosition().getX() || pos.getY() == getPosition().getY()))
			return true;
		return false;
	}
}
